/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package makao.server;

import java.util.ArrayList;
import java.util.Collections;
import java.util.EmptyStackException;
import shared.Card;
import shared.ThrowCards;

/**
 *
 * @author latata_2
 */
public class Game {

    private CardsPackStack packStack;
    public CardsStack cardsStack;
    private ArrayList<Player> players;
    private Player whoseTurn;
    private Player savedTurn = null;
    private Server server;
    public int demandCardType = 0;
    private Player whoDemand = null;
    public int demandCardSuit = 0;
    public int cardsToTake = 0;
    public int turnsToWait = 0;

    public Game(Server server, ArrayList<Player> players) {

        this.server = server;
        this.players = players;
        cardsToTake = 0;
        demandCardSuit = 0;
        demandCardType = 0;
        turnsToWait = 0;
        this.packStack = new CardsPackStack(2);
        Collections.shuffle(this.players);
        for (Player player : this.players) {
            player.getCards().clear();
            for (int i = 0; i < 5; i++) {
                if (player.getPlayerName().equals("latata")) {
                    player.giveCard(new Card(Card.HEART, i + 3));
                } else {
                    player.giveCard(packStack.popCard());
                }
            }
        }
        this.whoseTurn = this.players.get(0);
        this.cardsStack = new CardsStack();
        this.cardsStack.add(packStack.popStartCard());
        server.setServerState(Server.STATE_GAME_STARTED);
        //System.out.println("Rozpocząto grę.");
        server.sendPackageController.sendStartGameInfo(players, whoseTurn, cardsStack.getTopCard());

    }

    public void setServer(Server server) {
        this.server = server;
    }

    public Player getWhoseTurn() {
        return whoseTurn;
    }

    public int getCardsToTake() {
        return cardsToTake;
    }

    public int getTurnsToWait() {
        return turnsToWait;
    }

    public int getDemandCardType() {
        return demandCardType;
    }

    public int getDemandCardSuit() {
        return demandCardSuit;
    }

    public ArrayList<Player> getPlayers() {
        return players;
    }

    public Card getTopCard() {
        return cardsStack.getTopCard();
    }

    public void throwCards(Player player, ThrowCards throwCards) throws Exception {
//        System.out.println(player.hasCards(throwCards.getThrownCards()));
//        System.out.println(canThrow(throwCards.getThrownCards().get(0)));
//        System.out.println(canThrowAll(throwCards.getThrownCards()));
//        System.out.println(whoseTurn.getPlayerName());
        
        if (player == whoseTurn) {
            if (throwCards.getThrownCards().size() > 0
                    && player.hasCards(throwCards.getThrownCards())
                    && canThrow(throwCards.getThrownCards().get(0))
                    && canThrowAll(throwCards.getThrownCards())) {

                boolean canDemand = true;
                Card tempCard = null;
                boolean lastKingSpade = false;
                boolean demanded = false;
                int i = 0;
                for (Card card : throwCards.getThrownCards()) {
                    if (card.getType() == Card.JOKER) {
                        tempCard = card.getAsJoker();
                    } else {
                        tempCard = card;
                    }
                    switch (tempCard.getType()) {
                        case Card.TWO:
                            cardsToTake += 2;
                            break;
                        case Card.THREE:
                            cardsToTake += 3;
                            break;
                        case Card.KING:
                            if (tempCard.getSuit() == Card.HEART) {
                                cardsToTake += 5;
                            } else if (tempCard.getSuit() == Card.SPADE) {
                                cardsToTake += 5;
                                if (i == (throwCards.getThrownCards().size() - 1)) {
                                    lastKingSpade = true;
                                }
                            }
                            if (i == (throwCards.getThrownCards().size() - 1) && tempCard.getSuit() != Card.SPADE && tempCard.getSuit() != Card.HEART) {
                                cardsToTake = 0;
                            }
                            break;
                        case Card.FOUR:
                            turnsToWait++;
                            break;
                        case Card.ACE:
                            if (throwCards.getDemandCardSuit() > 0) {
                                demandCardSuit = throwCards.getDemandCardSuit();
                            }
                            break;
                        case Card.JACK:
                            demandCardType = throwCards.getDemandCardType();
                            if (demandCardType > 0) {
                                if (!player.hasCardType(demandCardType)) {
                                    canDemand = false;
                                } else {
                                    whoDemand = player;
                                    setPlayersDemandCardType(player, demandCardType);
                                    demanded = true;
                                }
                            } else {
                                whoDemand = null;
                                setPlayersDemandCardType(player, demandCardType);
                            }
                            break;

                    }
                    if (canDemand) {
                        if (!demanded && player == whoDemand) {
                            whoDemand = null;
                            demandCardType = 0;
                            setPlayersDemandCardType(player, demandCardType);
                        }
                        if (demanded) {
                            demandCardSuit = 0;
                        }
                        cardsStack.add(card);
                        player.removeCard(card);
                        if (player.getCards().isEmpty()) {
                            server.gameFinished(player);
                        }
                    }
                    i++;
                }
                if (canDemand) {
                    if(throwCards.getThrownCards().get(throwCards.getThrownCards().size()-1).getType() != Card.ACE) {
                        demandCardSuit = 0;
                    }
                    if (lastKingSpade) {
                        whoseTurn = getPlayerBackward();
                    } else {
                        whoseTurn = getPlayerForward();
                    }
                } else {
                    throw new Exception("Nie można żądać karty której nie posiadasz.");
                }
            } else {
                throw new Exception("Nie można położyć kart(y).");
            }
        } else {
            throw new Exception("Nie twoja kolej!");
        }
    }

    public void giveCardsToPlayer(Player player) throws Exception {
        if (turnsToWait == 0) {
            if (cardsToTake > 0) {
                for (int i = 0; i < cardsToTake; i++) {
                    player.giveCard(packStack.popCard());
                }
                cardsToTake = 0;
            } else {
                player.giveCard(packStack.popCard());
            }
            whoseTurn = getPlayerForward();
        } else {
            throw new Exception("Nie możesz wziąć karty. Musisz stać kolejkę/i lub położyć czwórkę.");
        }
    }

    public void waitTurns(Player player) throws Exception {
        if (turnsToWait > 0) {
            player.setTurnsToWait(turnsToWait - 1);
            turnsToWait = 0;
            whoseTurn = getPlayerForward();
        } else {
            throw new Exception("Brak kolejek do oczekiwania.");
        }
    }

    public boolean canThrow(Card card) {
        if (card.getType() == Card.JOKER) {
            card = card.getAsJoker();
        }
        Card topCard = cardsStack.getTopCard();
        if (topCard.getType() == Card.JOKER) {
            topCard = topCard.getAsJoker();
        }
        if (demandCardType == 0 && demandCardSuit == 0 && cardsToTake == 0 && turnsToWait == 0) {
            if (card.getType() == topCard.getType() || card.getSuit() == topCard.getSuit()) {
                return true;
            }
        } else if (demandCardType > 0) {
            if (card.getType() == demandCardType || (topCard.getType() == Card.JACK && card.getType() == Card.JACK)) {
                return true;
            }
        } else if (demandCardSuit > 0) {
            if (card.getSuit() == demandCardSuit || topCard.getType() == card.getType()) {
                return true;
            }
        } else if (cardsToTake > 0) {
            if (topCard.getType() == Card.KING && card.getType() == Card.KING && (card.getSuit() == Card.HEART || card.getSuit() == Card.SPADE)) {
                return true;
            } else if (card.getType() == topCard.getType()) {
                return true;
            }
        } else if (turnsToWait > 0) {
            if (topCard.getType() == card.getType()) {
                return true;
            }
        }
        return false;
    }

    private boolean canThrowAll(ArrayList<Card> thrownCards) {
        Card firstCard = null;
        for (Card card : thrownCards) {
            if (firstCard == null) {
                if (card.getType() == Card.JOKER) {
                    firstCard = card.getAsJoker();
                } else {
                    firstCard = card;
                }
            } else {
                Card tempCard = null;
                if (card.getType() == Card.JOKER) {
                    tempCard = card.getAsJoker();
                } else {
                    tempCard = card;
                }
                if (tempCard.getType() != firstCard.getType()) {
                    return false;
                }
            }
        }
        return true;
    }

    private Player getPlayerForward() {
        int index = players.indexOf(whoseTurn) + 1;
        Player nextPlayer = players.get(index % players.size());
        while (nextPlayer.getTurnsToWait() > 0) {
            nextPlayer.decreaseTurnsToWait();
            index = players.indexOf(nextPlayer) + 1;
            nextPlayer = nextPlayer = players.get(index % players.size());
        }
        return nextPlayer;
    }

    private Player getPlayerBackward() {
        int index = players.indexOf(whoseTurn) + (players.size() - 1);
        Player backPlayer = players.get(index % players.size());
        while (backPlayer.getTurnsToWait() > 0) {
            backPlayer.decreaseTurnsToWait();
            index = players.indexOf(backPlayer) + (players.size() - 1);
            backPlayer = players.get(index % players.size());
        }
        savedTurn = whoseTurn;
        return backPlayer;
    }

    private void setPlayersDemandCardType(Player player, int demandCardType) {
        for (Player p : players) {
            if (p == player) {
                p.setDemandCardType(demandCardType);
            } else {
                p.setDemandCardType(0);
            }
        }
    }

    void killUser() {
        whoseTurn = getPlayerForward();

    }
}
/*
 * kupka kart :)
 */

class CardsPackStack {

    private ArrayList<Card> pack;

    public CardsPackStack(int n) {
        pack = new ArrayList<Card>();
        if (n > 2 || n < 1) {
            n = 1;
        }
        for (int i = 0; i < n; i++) {
            for (int typeNo = 2; typeNo <= 14; typeNo++) {
                for (int suitNo = 1; suitNo <= 4; suitNo++) {
                    pack.add(new Card(suitNo, typeNo));
                }
            }
        }

        Collections.shuffle(pack);
    }

    public Card popCard() throws EmptyStackException {
        if (pack.isEmpty()) {
            throw new EmptyStackException();
        }
        return pack.remove(0);
    }

    public Card popStartCard() throws EmptyStackException {
        if (pack.isEmpty()) {
            throw new EmptyStackException();
        }
        Card card = null;
        int i = 0;
        do {
            card = pack.get(i);
            i++;
        } while (!card.isStartCard());
        return pack.remove(i - 1);
    }
}

/*
 * karty położone na stół
 */
class CardsStack extends ArrayList<Card> {

    public Card getTopCard() {
        return this.get(this.size() - 1);
    }
}
